#include "StateWalk.h"
#include "Logic/Entity/LivingEntity.h"
#include "Scheduler/Scheduler.h"
#include "Common.h"
#include "Message/Message.h"
#include "Message/MessagePump.h"
#include "Logic/State/StateMachine.h"


int MoveOneCellTask::count = 0;

void MoveOneCellTask::Execute(int id, int time, void* pUser)
{
	StateWalk* pState = (StateWalk*)pUser;
	pState->MoveOneCell();
	count--;
}

StateWalk::StateWalk(LivingEntity* parent) :State(FSM_STATE_WALK,parent)
{
	m_destCell = m_owner->GetPos();
}

void StateWalk::Enter()
{
	// do nothing because its update() will notify the render module.
}

void StateWalk::SetDestCell(const Vector2Di& dest)
{
	m_destCell = dest;
}

void StateWalk::Update(float dt)
{
	if (m_owner->GetPos() == m_destCell)
		return;

	//only execute once.
	if (MoveOneCellTask::count == 0)
	{
		MoveOneCellTask::count++;
		int excuteTime = s_Scheduler->GetClock().GetSystem() + m_owner->GetAttribute().walkSpeed * 20;
		s_Scheduler->Schedule(TASK_TIME, excuteTime, 0, -1, &m_moveTask, this, NULL);
	}
}

void StateWalk::MoveOneCell()
{
	//self terminated condition.
	if (m_owner->GetPos() == m_destCell)
	{// change to state none.
		DataMessage<int>* newMsg = new DataMessage<int>(ENTITY_MSG | UNICAST_MSG, MSGTYPE_CHANGE_STATE,FSM_STATE_NONE);
		newMsg->m_toID = m_owner->GetID();
		s_MessagePump->SendMsg(newMsg);
		return;
	}
	int dx = m_destCell.x() - m_owner->GetPos().x();
	int dy = m_destCell.y() - m_owner->GetPos().y();
	SetDirection(dx,dy);

	//self scheduled.
	int excuteTime = s_Scheduler->GetClock().GetSystem() + m_owner->GetAttribute().walkSpeed * 20;
	MoveOneCellTask::count++;
	s_Scheduler->Schedule(TASK_TIME, excuteTime, 0, -1, &m_moveTask, this, NULL);

	Vector2Di newPos = m_owner->GetPos();
	switch(m_owner->GetDirection())
	{
	case DIRECTION_DOWN :
		newPos.y() += 1;
		break;
	case DIRECTION_LDOWN:
		newPos.y() += 1;
		newPos.x() -= 1;
		break;
	case DIRECTION_LEFT:
		newPos.x() -= 1;
		break;
	case DIRECTION_LUP:
		newPos.x() -= 1;
		newPos.y() -= 1;
		break;
	case DIRECTION_UP:
		newPos.y() -= 1;
		break;
	case DIRECTION_RUP:
		newPos.y() -= 1;
		newPos.x() += 1;
		break;
	case DIRECTION_RIGHT:
		newPos.x() += 1;
		break;
	case DIRECTION_RDOWN:
		newPos.x() += 1;
		newPos.y() += 1;
		break;
	default :
		assert(0);
	}

	//Notify the Render module entity is moved. to make sure render is in step with logic module.
	LogicMsg data;
	data.from = m_owner->GetPos();
	data.to   = newPos;
	data.time = m_owner->GetAttribute().walkSpeed * 20;
	data.direction = m_owner->GetDirection();
	DataMessage<LogicMsg>* newMsg = new DataMessage<LogicMsg>(MODULE_MSG|BROADCAST_MSG, MSGTYPE_ENTITY_MOVE,data);
	newMsg->m_toID = m_owner->GetID();
	s_MessagePump->SendMsg(newMsg);

	m_owner->SetPos(newPos);
}

void StateWalk::SetDirection(int dx, int dy)
{
	if (dx > 0)
	{
		if (dy > 0)
		{
			m_owner->SetDirection(DIRECTION_RDOWN);
		}
		else if (dy == 0)
		{
			m_owner->SetDirection(DIRECTION_RIGHT);
		}
		else
		{
			m_owner->SetDirection(DIRECTION_RUP);
		}
	}
	else if (dx == 0)
	{
		if (dy > 0)
		{
			m_owner->SetDirection(DIRECTION_DOWN);
		}
		else if (dy == 0)
		{
			return;
		}
		else
		{
			m_owner->SetDirection(DIRECTION_UP);
		}
	}
	else
	{
		if (dy > 0)
		{
			m_owner->SetDirection(DIRECTION_LDOWN);
		}
		else if (dy == 0)
		{
			m_owner->SetDirection(DIRECTION_LEFT);
		}
		else
		{
			m_owner->SetDirection(DIRECTION_LUP);
		}
	}
}